package com.lingyun.mqttserver.util;

import lombok.Data;

public class ModbusAddressUtil {

    /**
     * 根据显示地址解析寄存器类型和实际地址
     * 支持标准地址和点分位地址
     */
    public static RegisterInfo parseShowAddress(String showAddress) {
        if (showAddress == null || showAddress.trim().isEmpty()) {
            throw new IllegalArgumentException("显示地址不能为空");
        }

        String addressStr = showAddress.trim();
        RegisterInfo info = new RegisterInfo();

        try {
            // 检查是否是点分位地址（如40001.1）
            if (addressStr.contains(".")) {
                return parseBitAddress(addressStr);
            } else {
                return parseWordAddress(Integer.parseInt(addressStr));
            }
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("无效的显示地址格式: " + showAddress);
        }
    }

    /**
     * 解析字地址（标准Modbus地址）
     */
    private static RegisterInfo parseWordAddress(Integer showAddress) {
        RegisterInfo info = new RegisterInfo();

        if (showAddress >= 1 && showAddress <= 9999) {
            info.setRegisterType("coil");
            info.setActualAddress(showAddress - 1);
            info.setIsBit(false);
        } else if (showAddress >= 10001 && showAddress <= 19999) {
            info.setRegisterType("discrete_input");
            info.setActualAddress(showAddress - 10001);
            info.setIsBit(false);
        } else if (showAddress >= 30001 && showAddress <= 39999) {
            info.setRegisterType("input_register");
            info.setActualAddress(showAddress - 30001);
            info.setIsBit(false);
        } else if (showAddress >= 40001 && showAddress <= 49999) {
            info.setRegisterType("holding_register");
            info.setActualAddress(showAddress - 40001);
            info.setIsBit(false);
        } else {
            throw new IllegalArgumentException("无效的显示地址: " + showAddress + "，有效范围: 1-9999, 10001-19999, 30001-39999, 40001-49999");
        }

        return info;
    }

    /**
     * 解析位地址（点分表示法，如40001.1）
     */
    private static RegisterInfo parseBitAddress(String bitAddress) {
        String[] parts = bitAddress.split("\\.");
        if (parts.length != 2) {
            throw new IllegalArgumentException("无效的位地址格式: " + bitAddress + "，正确格式如: 40001.1");
        }

        try {
            int wordAddress = Integer.parseInt(parts[0]);
            int bitIndex = Integer.parseInt(parts[1]);

            // 位索引从1开始到16
            if (bitIndex < 1 || bitIndex > 16) {
                throw new IllegalArgumentException("位索引必须在1-16范围内: " + bitIndex);
            }

            RegisterInfo info = new RegisterInfo();
            info.setBitIndex(bitIndex);
            info.setIsBit(true);

            if (wordAddress >= 30001 && wordAddress <= 39999) {
                info.setRegisterType("input_register");
                info.setActualAddress(wordAddress - 30001);
            } else if (wordAddress >= 40001 && wordAddress <= 49999) {
                info.setRegisterType("holding_register");
                info.setActualAddress(wordAddress - 40001);
            } else {
                throw new IllegalArgumentException("输入寄存器和保持寄存器必须带点，其他不能带点: " + wordAddress);
            }

            return info;
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("无效的位地址格式: " + bitAddress);
        }
    }

    /**
     * 根据寄存器类型和实际地址计算显示地址
     */
    public static String calculateShowAddress(String registerType, Integer actualAddress, String dataType, Integer bitIndex) {
        if (actualAddress == null || registerType == null) {
            return null;
        }

        // 如果是布尔类型且指定了位索引，并且是寄存器类型，使用点分表示法
        if ("bool".equalsIgnoreCase(dataType) && bitIndex != null && bitIndex >= 1 && bitIndex <= 16) {
            // 线圈和离散输入本身就是位设备，不需要点分表示法
            if ("coil".equalsIgnoreCase(registerType) || "discrete_input".equalsIgnoreCase(registerType)) {
                // 对于线圈和离散输入，直接返回标准地址，忽略位索引
                return calculateWordAddress(registerType, actualAddress).toString();
            } else if ("input_register".equalsIgnoreCase(registerType) || "holding_register".equalsIgnoreCase(registerType)) {
                // 只有寄存器类型的布尔变量才使用点分表示法
                Integer wordAddress = calculateWordAddress(registerType, actualAddress);
                if (wordAddress != null) {
                    return wordAddress + "." + bitIndex;
                }
            }
        }

        // 否则使用标准地址
        return calculateWordAddress(registerType, actualAddress).toString();
    }

    /**
     * 计算字地址
     */
    private static Integer calculateWordAddress(String registerType, Integer actualAddress) {
        if (actualAddress == null || registerType == null) {
            return null;
        }

        switch (registerType.toLowerCase()) {
            case "coil":
                return 1 + actualAddress;
            case "discrete_input":
                return 10001 + actualAddress;
            case "input_register":
                return 30001 + actualAddress;
            case "holding_register":
                return 40001 + actualAddress;
            default:
                return actualAddress;
        }
    }

    /**
     * 验证地址和数据类型是否匹配
     */
    public static void validateAddressAndDataType(String registerType, String dataType, Integer bitIndex) {
        if ("bool".equalsIgnoreCase(dataType)) {
            if ("input_register".equalsIgnoreCase(registerType) || "holding_register".equalsIgnoreCase(registerType)) {
                // 寄存器类型的布尔变量必须指定位索引
                if (bitIndex == null) {
                    throw new IllegalArgumentException("寄存器类型的布尔变量必须指定位索引(1-16)");
                }
                if (bitIndex < 1 || bitIndex > 16) {
                    throw new IllegalArgumentException("位索引必须在1-16范围内: " + bitIndex);
                }
            } else if ("coil".equalsIgnoreCase(registerType) || "discrete_input".equalsIgnoreCase(registerType)) {
                // 线圈和离散输入本身就是位设备，不应该有位索引
                if (bitIndex != null) {
                    throw new IllegalArgumentException("线圈和离散输入类型不能有位索引，因为它们本身就是位设备");
                }
            }
        } else {
            // 非布尔类型不应该有位索引
            if (bitIndex != null) {
                throw new IllegalArgumentException("非布尔数据类型不能有位索引");
            }
        }
    }

    /**
     * 将位索引转换为实际的位掩码（0-based）
     */
    public static int convertBitIndexToMask(Integer bitIndex) {
        if (bitIndex == null || bitIndex < 1 || bitIndex > 16) {
            throw new IllegalArgumentException("位索引必须在1-16范围内: " + bitIndex);
        }
        return bitIndex - 1; // 转换为0-based
    }

    /**
     * 将位掩码转换为位索引（1-based）
     */
    public static int convertMaskToBitIndex(Integer bitMask) {
        if (bitMask == null || bitMask < 0 || bitMask > 15) {
            throw new IllegalArgumentException("位掩码必须在0-15范围内: " + bitMask);
        }
        return bitMask + 1; // 转换为1-based
    }

    @Data
    public static class RegisterInfo {
        private String registerType;
        private Integer actualAddress;
        private Boolean isBit = false;
        private Integer bitIndex; // 1-16
    }
}